libobs_simple\sources\linux\sources/
pipewire_capture.rs

1use libobs_simple_macro::{obs_object_builder, obs_object_updater};
2use libobs_wrapper::{
3    data::ObsDataGetters,
4    run_with_obs,
5    sources::{ObsSourceBuilder, ObsSourceRef},
6    unsafe_send::Sendable,
7    utils::{traits::ObsUpdatable, ObsError},
8};
9
10use crate::sources::macro_helper::define_object_manager;
11
12#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13/// PipeWire source type
14pub enum ObsPipeWireSourceType {
15    /// Screen capture via desktop portal
16    DesktopCapture,
17    /// Camera capture via camera portal  
18    CameraCapture,
19}
20/*
21define_object_manager!(
22    #[derive(Debug)]
23    /// A source for PipeWire screen/camera capture.
24    ///
25    /// PipeWire is a modern multimedia framework for Linux that handles audio and video.
26    /// This source can capture screen content through the desktop portal or camera
27    /// content through the camera portal, providing sandboxed capture capabilities.
28    struct PipeWireDesktopCaptureSource("pipewire-desktop-capture-source") for ObsSourceRef {
29        /// Restore token for reconnecting to previous sessions
30        #[obs_property(type_t = "string", settings_key="RestoreToken")]
31        restore_token: String,
32
33        /// Whether to show cursor (for screen capture)
34        #[obs_property(type_t = "bool", settings_key="ShowCursor")]
35        show_cursor: bool,
36    }
37);
38 */
39
40#[obs_object_builder("pipewire-desktop-capture-source")]
41pub struct PipeWireDesktopCaptureSourceBuilder {
42    /// Restore token for reconnecting to previous sessions
43    #[obs_property(type_t = "string", settings_key = "RestoreToken")]
44    restore_token: String,
45
46    /// Whether to show cursor (for screen capture)
47    #[obs_property(type_t = "bool", settings_key = "ShowCursor")]
48    show_cursor: bool,
49}
50
51#[obs_object_updater("pipewire-desktop-capture-source", ObsSourceRef)]
52pub struct PipeWireDesktopCaptureSourceUpdater {
53    /// Whether to show cursor (for screen capture)
54    #[obs_property(type_t = "bool", settings_key = "ShowCursor")]
55    show_cursor: bool,
56}
57
58#[obs_object_builder("pipewire-window-capture-source")]
59pub struct PipeWireWindowCaptureSourceBuilder {
60    /// Restore token for reconnecting to previous sessions
61    #[obs_property(type_t = "string", settings_key = "RestoreToken")]
62    restore_token: String,
63
64    /// Whether to show cursor (for screen capture)
65    #[obs_property(type_t = "bool", settings_key = "ShowCursor")]
66    show_cursor: bool,
67}
68
69#[obs_object_updater("pipewire-window-capture-source", ObsSourceRef)]
70pub struct PipeWireWindowCaptureSourceUpdater {
71    /// Whether to show cursor (for screen capture)
72    #[obs_property(type_t = "bool", settings_key = "ShowCursor")]
73    show_cursor: bool,
74}
75
76#[obs_object_builder("pipewire-screen-capture-source")]
77/// This struct is used to build a PipeWire screen capture source (so window + desktop capture).
78pub struct PipeWireScreenCaptureSourceBuilder {
79    /// Restore token for reconnecting to previous sessions
80    #[obs_property(type_t = "string", settings_key = "RestoreToken")]
81    restore_token: String,
82
83    /// Whether to show cursor (for screen capture)
84    #[obs_property(type_t = "bool", settings_key = "ShowCursor")]
85    show_cursor: bool,
86}
87
88#[obs_object_updater("pipewire-screen-capture-source", ObsSourceRef)]
89/// This struct is used to update a PipeWire screen capture source (so window + desktop capture).
90pub struct PipeWireScreenCaptureSourceUpdater {
91    /// Whether to show cursor (for screen capture)
92    #[obs_property(type_t = "bool", settings_key = "ShowCursor")]
93    show_cursor: bool,
94}
95
96define_object_manager!(
97    #[derive(Debug)]
98    /// A source for PipeWire camera capture via camera portal.
99    ///
100    /// This source captures video from camera devices through PipeWire's camera portal,
101    /// providing secure access to camera devices in sandboxed environments.
102    struct PipeWireCameraSource("pipewire-camera-source") for ObsSourceRef {
103        /// Camera device node (e.g., "/dev/video0")
104        #[obs_property(type_t = "string")]
105        camera_id: String,
106
107        /// Video format (FOURCC as string)
108        #[obs_property(type_t = "string")]
109        video_format: String,
110
111        /// Resolution as "width x height"
112        #[obs_property(type_t = "string")]
113        resolution: String,
114
115        /// Framerate as "num/den"
116        #[obs_property(type_t = "string")]
117        framerate: String,
118    }
119);
120
121/// This trait provides additional methods for PipeWire sources.
122pub trait PipeWireSourceExtTrait {
123    /// Gets the restore token used for reconnecting to previous sessions for `pipewire-desktop-capture-source` and `pipewire-window-capture-source` sources.
124    ///
125    /// As of right now, there is no callback or signal to notify when the token has been set, you have to call this method to get the restore token.
126    ///
127    /// The restore token will most probably be of `Some(String)` after the user has selected a screen or window to capture.
128    fn get_restore_token(&self) -> Result<Option<String>, ObsError>;
129}
130
131impl PipeWireSourceExtTrait for ObsSourceRef {
132    fn get_restore_token(&self) -> Result<Option<String>, ObsError> {
133        if self.id() != "pipewire-desktop-capture-source"
134            && self.id() != "pipewire-window-capture-source"
135            && self.id() != "pipewire-screen-capture-source"
136        {
137            return Err(ObsError::InvalidOperation(format!("Can't call 'get_restore_token' on a source of id {}. Expected 'pipewire-desktop-capture-source', 'pipewire-window-capture-source' or 'pipewire-screen-capture-source'", self.id())));
138        }
139
140        let source_ptr = Sendable(self.as_ptr());
141        run_with_obs!(self.runtime(), (source_ptr), move || unsafe {
142            libobs::obs_source_save(source_ptr);
143        })?;
144
145        let settings = self.get_settings()?;
146        let token = settings.get_string("RestoreToken")?;
147        Ok(token)
148    }
149}
150
151impl PipeWireDesktopCaptureSourceBuilder {
152    /// Enable cursor capture for screen recording
153    pub fn with_cursor(self) -> Self {
154        self.set_show_cursor(true)
155    }
156}
157
158impl PipeWireCameraSourceBuilder {
159    /// Set resolution using width and height values
160    pub fn set_resolution_values(self, width: u32, height: u32) -> Self {
161        self.set_resolution(format!("{}x{}", width, height))
162    }
163
164    /// Set framerate using numerator and denominator
165    pub fn set_framerate_values(self, num: u32, den: u32) -> Self {
166        self.set_framerate(format!("{}/{}", num, den))
167    }
168}
169
170impl ObsSourceBuilder for PipeWireDesktopCaptureSourceBuilder {}
171impl ObsSourceBuilder for PipeWireWindowCaptureSourceBuilder {}
172impl ObsSourceBuilder for PipeWireScreenCaptureSourceBuilder {}
173impl ObsSourceBuilder for PipeWireCameraSourceBuilder {}